import java.io.*;

public class SharedObject implements Serializable, SharedObject_itf {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final int request = 50;

	public enum StateLock {NL, RLT, WLT, RLC, WLC, RLT_WLC}; // représentation des etat des verrous côté client
	private Integer id; //id du descripteur d'objet
	public StateLock lock; //verrou
	public Object obj; //pointeur sur l'objet effectif
	
	public SharedObject(int id, Object o) {
		this.id = id;
		this.lock = StateLock.NL;
		this.obj = o;
	}

	public int getId() {
		return id;
	}

	// invoked by the user program on the client node
    public synchronized void lock_read() {
    	switch(lock) {
	    	case WLC: lock = StateLock.RLT_WLC; break ;
	    	case RLC: lock = StateLock.RLT; break;
	    	case NL:
	    		obj = Client.lock_read(id);
	    		while (obj == null) {
	    			try {
	    				wait(request);
	    			} catch(InterruptedException ex) {
	    				ex.printStackTrace();
	    			}
	    			obj = Client.lock_read(id);
	    		}
	    		lock = StateLock.RLT;
	    		break ;
    	}
    }

    // invoked by the user program on the client node
    public synchronized void lock_write() {
    	switch (this.lock) {
		case WLC: lock = StateLock.WLT; break;
		case NL:
		case RLC:
			/* Pour compenser la non invocation de invalidate_reader
			∗ par le serveur sur le client emetteur.
			*/
			lock = StateLock.NL;
			obj = Client.lock_write(id);
			while (obj == null) {
				try {
					wait(request);
				} catch(InterruptedException ex){
					ex.printStackTrace();
				}
				obj = Client.lock_write(id);
			}
			lock = StateLock.WLT;
		break;
		default : break;
    	}
    }

    // invoked by the user program on the client node
    public synchronized void unlock() {
    	switch ( this.lock ) {
    		case RLT: this.lock = StateLock.RLC; 
    		break ;
    		case RLT_WLC: this.lock = StateLock.WLC;
    		case WLT: this.lock = StateLock.WLC; 
    		break;
    	}
    	notify(); //notification sur l'objet 
    }


    // callback invoked remotely by the server
    public synchronized Object reduce_lock() {
    	switch (this.lock) {
    		case WLT:
    		try {
    			wait(); //attente du unlock
    		} catch ( InterruptedException ex ) {
    		ex.printStackTrace() ;
    		}
    		case WLC: this.lock = StateLock.RLC; 
    		break ;
    		case RLT_WLC: this.lock = StateLock.RLT; 
    		break ;
    	}
    	return this.obj ; //retour de l'objet libéré du verrou d'écriture
    }
    

    // callback invoked remotely by the server
    public synchronized void invalidate_reader() {
    	 switch ( this.lock ) {
    	 	case RLT:
    	 		try {
    	 			wait();
    	 		} catch (InterruptedException ex) {
    	 			ex.printStackTrace();
    	 		}
    	 	case RLC : this.lock = StateLock.NL; 
    	 	break ;
    	 }
     }
    

    public synchronized Object invalidate_writer() {
    	switch ( this.lock ) {
    		case RLT_WLC:
    			try {
    				wait();
    			} catch ( InterruptedException ex ) {
    				ex.printStackTrace() ;
    			} 
    		case WLT:
    			try {
    				wait();
    			} catch ( InterruptedException ex ) {
    				ex.printStackTrace() ;
    			}
    		case WLC: lock = StateLock.NL; 
    		break ;
    	}
    	return this.obj ;    	  	
    }
}
